/****************************************************************************
 * bTreeTest.c -
 *     Test the BTree program
 ***************************************************************************/
#include  "bTree.h"
#include  "../query_handler/query_handler.h"

#include  <stdio.h>
#include  <stdlib.h>
#include  <assert.h>
#include  <values.h>


/*= Start of Code =========================================================*/
#ifndef  RAND_MAX
#define  RAND_MAX    ((1 << (sizeof( int ) * 8 - 1)) - 1)
#endif  // RAND_MAX

static double    doubleRand( void ) 
{
    return  (double)rand()/(double)RAND_MAX;
}


int compare_offt(const off_t * a, const off_t * b) {
  if(*a == *b) { return EQ; }
  if(*a <  *b) { return LT; }
  return GT;
}

const void* print_offt(const off_t * a, void * n) {
  printf("%ld\n", (long)*(off_t*)a);
  return a;
}

#define NUM_OBJECTS 5000

int  main ()
{

    int  ind;
    off_t inserted[NUM_OBJECTS];
    off_t t;
    //    struct btree *tree =btree_new_memory(sizeof (off_t));

    struct store * rand  =store_open_cached("rand", "rand.fat", sizeof(off_t), 100, 20);
    struct btree *tree = btree_new_cached(rand, "rand.bTree", "rand.bTree.fat", 20, (int(*)(const void *, const void *))compare_offt);

    for  ( ind = 0; ind < NUM_OBJECTS; ind++ ) {
      off_t new = store_new(rand);
      off_t * new_data = store_read(rand, new);
      inserted[ind] = 2 * (off_t) (100000.0 * doubleRand());
      printf(".");
      fflush(stdout);
      
      *new_data = inserted[ind];  
      store_write(rand, new);
      store_release(rand, new);
    
      btree_insert( tree, new );

    }
    
    
    printf("Closing tree after inserts...\n");
    fflush(stdout);
    
    btree_close(tree);
    tree =btree_new_cached(rand, "rand.bTree", "rand.bTree.fat", 20, (int(*)(const void *, const void *))compare_offt);
	
    btree_print( tree );        
    
    printf("Closing tree after print...\n");
    fflush(stdout);
    
    
    btree_close(tree);
    tree =btree_new_cached(rand, "rand.bTree", "rand.bTree.fat", 20, (int(*)(const void *, const void *))compare_offt);

    
    for (ind = 0; ind < NUM_OBJECTS; ind++) {
      assert(btree_find(tree, &(inserted[ind])) == 1);
      t = inserted[ind]+1;
      assert(btree_find(tree, &(t)) == 0);

    }

    printf("Closing tree after finds...\n");
    fflush(stdout);

    btree_close(tree);
    tree =btree_new_cached(rand, "rand.bTree", "rand.bTree.fat", 20, (int(*)(const void *, const void *))compare_offt);
    

    for(ind = 0; ind < NUM_OBJECTS; ind+=10) {
      int j;
      off_t new = store_new(rand);
      off_t * new_ptr = store_read(rand, new);
      int hit_count = 0;
      off_t tmp;
      *new_ptr = inserted[ind] + 1;
      store_write(rand, new);
      store_release(rand, new);
      for(j = 0; j < ind / 10; j++) {
	
	btree_insert(tree, new);
      }

      tmp = inserted[ind] + 1;
      btree_query(tree, &(tmp), (void*(*)(const void*, void*))count_hits, &hit_count);


      assert (hit_count == ind/10);

      for(j = 0; j < ind / 10; j++) {
	
	assert(btree_delete(tree, &tmp));
      }
      assert(!btree_delete(tree, &tmp));

      hit_count =0;


      btree_query(tree, &(tmp), (void*(*)(const void*, void*))count_hits, &hit_count);

      assert(hit_count == 0);

    }

    printf("Closing tree after testing query...\n");
    fflush(stdout);

    btree_close(tree);
    tree =btree_new_cached(rand, "rand.bTree", "rand.bTree.fat", 20, (int(*)(const void *, const void *))compare_offt);


    for (ind = 0; ind < NUM_OBJECTS; ind++) {
      off_t num = tree->entries_num;
//      assert(tree->entries_num == NUM_OBJECTS - ind);
      assert(btree_find(tree, &(inserted[ind])));

      assert(btree_delete(tree, &(inserted[ind])));
      t = inserted[ind] + 1;
      //      assert(!btree_delete(tree, &t));

      assert(tree->entries_num + 1 == num);
      
    }
    //    assert(tree->entries_num == 0);

    printf("Closing tree after deletes...\n");
    fflush(stdout);

    btree_close(tree);

    //    btree_term( tree );

    return  0;
}
